A computer programmer, or user, typically writes a computer program in a one of several high level programming languages. This program, referred to herein as a "user program," is then translated into an associated object code file by a compiler and linked with other object code files to produce an executable "image file" which is executed, or run, by processors in a computer system. Accordingly, the system may also include one or more preprocessors which translate the user program into a related source code file, before the compiler converts the source code to object code and sends it to the linker.
The translations which the preprocessors perform may, for example, involve substituting several lines of code for a single high level language command. This changes program line numbers. The translations may also involve altering variable names, for example, changing the names from names which are valid in the high level language to names which are valid in the language(s) used by the preprocessors and/or the compiler. Also, the translation may involve substituting one or more lines of code for a macro, which may be a part of a high level language command.
Computer systems also typically include analysis tools which help a user understand how the systems interpret and execute his or her program. One of these analysis tools is a "debugger," which is an interactive tool that enables a user essentially to interrupt the execution of a program and to view, for example, the values of variables at the time of interruption. The debugger thus allows a user to determine if the program is assigning expected, or realistic, intermediate values to these variables. The debugger also interrupts the execution of the program when an execution error occurs and displays an error message.
The debugger receives information from the linker relating to the relationships between locations and symbols in the image file and lines of code and "symbols" in the source code file. The term "symbols" refers to variables, routines, literals, objects, macros, fields, and any other type of program entity. The linker receives from the compiler a debugger symbol table which describes these relationships for a particular object file. The linker concatenates the tables from each of the linked object code files and produces the image file debugger table, which is then made available to the debugger. The debugger interprets the debugger symbol table to provide to a user information relating to the execution of the program and the intermediate values of symbols, in terms of the lines of code and symbol names of the source code file. The user must then relate this information to the user program in order to modify that program in an attempt to achieve the proper variable values, and correct the execution errors. The user may then, if necessary, send the modified program through the preprocessors and the compiler for further debugging.
For a user to relate the information provided by the debugger to the symbols and code lines of the user program, the user must know how the compiler and each of the preprocessors translated the lines of the user program and/or re-named the symbols. Most users can not readily follow these preprocessor and compiler translations, and thus, they have a difficult time understanding how the system is interpreting their programs. Accordingly, they cannot readily revise the program to produce the desired results.
Systems which use the programming language "C" offer users some help in understanding the translation of their programs. The C language preprocessors include in their preprocessor output files #line directives, which enable the preprocessors to relate lines of the preprocessor output files to lines of the preprocessor input files. Each intermediate preprocessor interprets the #line directive information provided to it by the preceding preprocessor by relating its output file back to the user program, which is the input file of the first preprocessor. Similarly, the C-compiler relates the locations and symbols of the object file back to the user program and provides this information to the linker. The linker includes this information in the debugger symbol table, which it makes available to the debugger. The debugger then uses this information to relate locations in the image file to various lines of the user program.
While the #line directives aid a user in understanding the relationship between particular locations of the image file and lines of the user program, they do not provide a user with information directly relating to the translations of symbol names, or allow a user to examine the intermediate symbol or code line translations performed by the preprocessors. Accordingly, the user may still not understand how the system interprets and/or executes his or her program, and more importantly, how to change the user program to achieve a desired result. Also, the #line directives supply the user with correct information only if all the preprocessors and the compiler understand the directives, that is, only if they are all compatible with the C language.
What is needed is a language-independent mechanism for interpreting translations performed in transforming a user program to a source code file. Such a mechanism should operate with the debugger to provide information to a user in terms of the code lines and symbol names of the user program, while also making available to the user the corresponding code lines and symbol names in the source code file and the intermediate preprocessor files. Further, what is needed is a mechanism which determines intermediate values of symbols, using the user program names of these symbols, regardless of how many times the symbol names and/or the related lines of code change during preprocessing and compiling.